// CGWorkView.cpp : implementation of the CCGWorkView class
//
#include "stdafx.h"
#include "CGWork.h"

#include "CGWorkDoc.h"
#include "CGWorkView.h"

#include "Drawer.h"
#include "World.h"
#include "Edge.h"
#include "SensibilityDialog.h"
#include "FinenessDialog.h"
#include "ImageBitmap.h"
#include "Z_Buffer.h"
#include "Lighter.h"
#include "PolygonData.h"
#include "PngPlotter.h"
#include "RenderToFileDialog.h"
#include "SelectBackgroundImageDialog.h"
#include "AntiAliazer.h"
#include "textureDlg2.h"

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <process.h>
#include <string>
using std::cout;
using std::endl;
using std::string;
#include "MaterialDlg.h"
#include "LightDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "PngWrapper.h"
#include "iritSkel.h"


// For Status Bar access
#include "MainFrm.h"

// Use this macro to display text messages in the status bar.
#define STATUS_BAR_TEXT(str) (((CMainFrame*)GetParentFrame())->getStatusBar().SetWindowText(str))


/////////////////////////////////////////////////////////////////////////////
// CCGWorkView

IMPLEMENT_DYNCREATE(CCGWorkView, CView)

	BEGIN_MESSAGE_MAP(CCGWorkView, CView)
		//{{AFX_MSG_MAP(CCGWorkView)
		ON_WM_ERASEBKGND()
		ON_WM_CREATE()
		ON_WM_DESTROY()
		ON_WM_SIZE()
		ON_COMMAND(ID_FILE_LOAD, OnFileLoad)
		ON_COMMAND(ID_VIEW_ORTHOGRAPHIC, OnViewOrthographic)
		ON_UPDATE_COMMAND_UI(ID_VIEW_ORTHOGRAPHIC, OnUpdateViewOrthographic)
		ON_COMMAND(ID_VIEW_PERSPECTIVE, OnViewPerspective)
		ON_UPDATE_COMMAND_UI(ID_VIEW_PERSPECTIVE, OnUpdateViewPerspective)
		ON_COMMAND(ID_ACTION_ROTATE, OnActionRotate)
		ON_UPDATE_COMMAND_UI(ID_ACTION_ROTATE, OnUpdateActionRotate)
		ON_COMMAND(ID_ACTION_SCALE, OnActionScale)
		ON_UPDATE_COMMAND_UI(ID_ACTION_SCALE, OnUpdateActionScale)
		ON_COMMAND(ID_ACTION_TRANSLATE, OnActionTranslate)
		ON_UPDATE_COMMAND_UI(ID_ACTION_TRANSLATE, OnUpdateActionTranslate)
		ON_COMMAND(ID_AXIS_X, OnAxisX)
		ON_UPDATE_COMMAND_UI(ID_AXIS_X, OnUpdateAxisX)
		ON_COMMAND(ID_AXIS_Y, OnAxisY)
		ON_UPDATE_COMMAND_UI(ID_AXIS_Y, OnUpdateAxisY)
		ON_COMMAND(ID_AXIS_Z, OnAxisZ)
		ON_COMMAND(ID_AXIS_XY, OnAxisXY)
		ON_UPDATE_COMMAND_UI(ID_AXIS_Z, OnUpdateAxisZ)
		ON_COMMAND(ID_LIGHT_SHADING_FLAT, OnLightShadingFlat)
		ON_UPDATE_COMMAND_UI(ID_LIGHT_SHADING_FLAT, OnUpdateLightShadingFlat)
		ON_COMMAND(ID_LIGHT_SHADING_GOURAUD, OnLightShadingGouraud)
		ON_UPDATE_COMMAND_UI(ID_LIGHT_SHADING_GOURAUD, OnUpdateLightShadingGouraud)
		ON_COMMAND(ID_LIGHT_CONSTANTS, OnLightConstants)
		
		// Added
		ON_WM_MOUSEMOVE()
		ON_WM_LBUTTONDOWN()
		ON_COMMAND(ID_LIGHT_MATERIALVARS,onUpdatMaterialvars)
		ON_COMMAND(ID_SHADING_PHONG,OnLightShadingPhong)
		ON_UPDATE_COMMAND_UI(ID_SHADING_PHONG,OnUpdateLightShadingPhong)
		ON_COMMAND(ID_ADITIONALACTIONS_BOUNDINGBOX, OnUpdateBoundingBox)
		ON_COMMAND(ID_ADITIONALACTIONS_VERTEXNORMALS, OnUpdateVertexNormals)
		ON_COMMAND(ID_ADITIONALACTIONS_POLYGONSNORMAL , OnUpdatePolygonsNormals)
		ON_COMMAND(ID_ADITIONALACTIONS_INCREASEPERSPECTIVDD10 , OnIncreasePerspectiveD10)
		ON_COMMAND(ID_ADITIONALACTIONS_DECREASEPERSPECTIVDD10 , OnDecreasePerspectiveD10)
		ON_COMMAND(ID_CHANGECOLORS_NORMALS , OnChangeColorNormals)
		ON_COMMAND(ID_CHANGECOLORS_VERTEX , OnChangeColorVertex)
		ON_COMMAND(ID_CHANGECOLORS_BACKGROUND , OnChangeColorBackground)
		ON_COMMAND(ID_OPTIONS_MOUSESENSITIVITY , OnMouseSensitivity)
		ON_COMMAND(ID_OPTIONS_FINENESSCONTROL , OnFinenessControl)
		ON_COMMAND(ID_OPTIONS_SWITCHTOVIEWSPACE , OnViewSpace)
		ON_COMMAND(ID_OPTIONS_SWITCHTOOBJECTSPACE, OnObjectSpace)
		ON_COMMAND(ID_OPTIONS_SETCLICKTOLIGHT, OnSetCTL)
		ON_COMMAND(ID_OPTIONS_UNSETCLICKTOLIGHT, OnUnSetCTL)
		ON_COMMAND(ID_RENDER_ONSCREEN, OnRenderOnScreen)
		ON_COMMAND(ID_RENDER_TOFILE, OnRenderOnFile)
		ON_COMMAND(ID_OPTIONS_SETIMAGEBACKGROUND, OnSetImageBackground)
		ON_COMMAND(ID_TEXTURE_WOOD32838,onUpdatTextureWood)
		ON_COMMAND(ID_TEXTURE_MARBEL32839,onUpdatTextureMarbel)
		ON_COMMAND(ID_TEXTURE_RUST,onUpdatTextureRust)
		ON_COMMAND(ID_TEXTURE_ARMY,onUpdatTextureArmy)
		ON_COMMAND(ID_TEXTURE_EARTH,onUpdatTextureEarth)
		ON_COMMAND(ID_TEXTURE_CUSTO,onUpdateTextureCustom)
		ON_COMMAND(ID_TEXTURE_REPTILESKIN,onUpdateTextureReptileSkin)
		ON_COMMAND(ID_TEXTURE_ADDBASE,onAddBase)
		ON_COMMAND(ID_LIGHT_SHADOWS,addShadows)

		ON_COMMAND(ID_LIGHT_FOG,onActivateFog)
		ON_COMMAND(ID_LIGHT_FOGCOLOR,onSetFogColor)

		ON_WM_KEYDOWN()

		//}}AFX_MSG_MAP
		ON_COMMAND(ID_NORMAL_INVERSE, &CCGWorkView::OnNormalInverse)
		ON_COMMAND(ID_OPTIONS_SWITCHBACKFACECULLING, &CCGWorkView::OnOptionsSwitchbackfaceculling)
		ON_COMMAND(ID_TRANSPARENCY_ENABLE, &CCGWorkView::OnTransparencyEnable)
		ON_COMMAND(ID_TRANSPARENCY_DISABLE, &CCGWorkView::OnTransparencyDisable)
		ON_COMMAND(ID_ANTIALIASING_ENABLE, &CCGWorkView::OnAntialiasingNone)
		ON_COMMAND(ID_ANTIALIASING_DISABLE, &CCGWorkView::OnAntialiasingBox)
		ON_COMMAND(ID_ANTIALIASING_B, &CCGWorkView::OnAntialiasingGauss)
		ON_COMMAND(ID_ANTIALIASING_TRIANGLE, &CCGWorkView::OnAntialiasingTriangle)
		ON_COMMAND(ID_ANTIALIASING_SINC, &CCGWorkView::OnAntialiasingSinc)
		ON_COMMAND(ID_ANTIALIASING_FILTERSIZE3X3, &CCGWorkView::OnAntialiasingFiltersize3x3)
		ON_COMMAND(ID_ANTIALIASING_FILTERSIW, &CCGWorkView::OnAntialiasingFilterSize5x5)
	END_MESSAGE_MAP()


	// A patch to fix GLaux disappearance from VS2005 to VS2008
	void auxSolidCone(GLdouble radius, GLdouble height) {
		GLUquadric *quad = gluNewQuadric();
		gluQuadricDrawStyle(quad, GLU_FILL);
		gluCylinder(quad, radius, 0.0, height, 20, 20);
		gluDeleteQuadric(quad);
	}

	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView construction/destruction

	CCGWorkView::CCGWorkView()
	{
		// Set default values
		m_nAxis = ID_AXIS_X;
		m_nAction = ID_ACTION_ROTATE;
		m_nView = ID_VIEW_ORTHOGRAPHIC;	
		m_bIsPerspective = false;
		m_bIsBoundingBox = false;
		m_bIsVertexNormals = false;
		m_bIsPolygonNormals = false;
		m_bIsClickToLight = false;
		m_renderOnScreen = false;
		m_imageBackground = false;
		m_backface_culling = false;
		m_transparency = false;
		inAnimation = false;
		lastRenderOnScreen = 1000;
		fineness = 20;
		rotateSensitivity = 10;
		translateSensitivity = 10;
		scaleSensitivity = 10;

		m_nLightShading = ID_LIGHT_SHADING_FLAT;

		m_lMaterialAmbient = 0.2;
		m_lMaterialDiffuse = 0.8;
		m_lMaterialSpecular = 1.0;
		m_nMaterialCosineFactor = 32;

		mouseDown = HW2::Coordinates(-1,-1);

		//init the first light to be enabled
		m_lights[LIGHT_ID_1].enabled=true;
	}

	CCGWorkView::~CCGWorkView()
	{
	}


	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView diagnostics

#ifdef _DEBUG
	void CCGWorkView::AssertValid() const
	{
		CView::AssertValid();
	}

	void CCGWorkView::Dump(CDumpContext& dc) const
	{
		CView::Dump(dc);
	}

	CCGWorkDoc* CCGWorkView::GetDocument() // non-debug version is inline
	{
		ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCGWorkDoc)));
		return (CCGWorkDoc*)m_pDocument;
	}
#endif //_DEBUG


	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView Window Creation - Linkage of windows to CGWork

	BOOL CCGWorkView::PreCreateWindow(CREATESTRUCT& cs)
	{
		// TODO: Modify the Window class or styles here by modifying
		//  the CREATESTRUCT cs

		// An CGWork window must be created with the following
		// flags and must NOT include CS_PARENTDC for the
		// class style.

		cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

		return CView::PreCreateWindow(cs);
	}



	int CCGWorkView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
	{
		if (CView::OnCreate(lpCreateStruct) == -1)
			return -1;

		InitializeCGWork();
		return 0;
	}


	// This method initialized the CGWork system.
	BOOL CCGWorkView::InitializeCGWork()
	{
		m_pDC = new CClientDC(this);

		if ( NULL == m_pDC ) { // failure to get DC
			::AfxMessageBox("Couldn't get a valid DC.");
			return FALSE;
		}

		return TRUE;
	}


	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView message handlers

	void CCGWorkView::OnSize(UINT nType, int cx, int cy) 
	{
		CView::OnSize(nType, cx, cy);

		if ( 0 >= cx || 0 >= cy ) {
			return;
		}

		// save the width and height of the current window
		m_WindowWidth = cx;
		m_WindowHeight = cy;


		// compute the aspect ratio
		// this will keep all dimension scales equal
		m_AspectRatio = (GLdouble)m_WindowHeight/(GLdouble)m_WindowWidth;

		HW2::Drawer::get().resize(cx, cy);

	}


	BOOL CCGWorkView::SetupViewingFrustum(void)
	{
		return TRUE;
	}


	// This viewing projection gives us a constant aspect ration. This is done by
	// increasing the corresponding size of the ortho cube.
	BOOL CCGWorkView::SetupViewingOrthoConstAspect(void)
	{
		return TRUE;
	}

	BOOL CCGWorkView::OnEraseBkgnd(CDC* pDC) 
	{
		// Windows will clear the window with the background color every time your window 
		// is redrawn, and then CGWork will clear the viewport with its own background color.

		return CView::OnEraseBkgnd(pDC);
		//return true;
	}

	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView drawing
	/////////////////////////////////////////////////////////////////////////////

	struct params
	{
		int start, end;
		std::vector<HW2::ImageBitmap> bitmaps;
	};

	void CCGWorkView::render(HW2::Plotter &p, int height, int width)
	{
		HW2::Drawer oldDrawer = HW2::Drawer::get();
		
		HW2::Drawer &d = HW2::Drawer::get();
		HW2::World &w = HW2::World::get();
		HW2::Color bg = w.BackgroundColor;

		int filterSize = w.filterSize;
		int filterType = w.filterType;
		if(filterType == 0)
			filterSize = 1;

		d.resize(width*filterSize, height*filterSize);

		HW2::Z_Buffer z_buffer(width*filterSize, height*filterSize);
		
		if(m_imageBackground)
		{
			backgroundImage.draw(z_buffer, width, height, filterSize);
		}
		else
		{
			z_buffer.fillBackground(bg);
		}


		for(unsigned int i = 0; i< w.polygons.size(); ++i)
		{
			// BackFace Culling
			if(!m_backface_culling || d.transform(w.polygons[i].normal.unitVector).Z() > 0)
			{
				HW2::PolygonData pd = d.generatePolygonData(w.polygons[i]);
				pd.draw(z_buffer);
			}
			//pd.draw(p);
		}
		HW2::AntiAliazer anti(width, height, filterType,filterSize);

		if(m_transparency)
			z_buffer.drawTransparency(anti);
		else
			z_buffer.draw(anti);

		anti.draw(p);

		HW2::Drawer::get() = oldDrawer;
	}

	void CCGWorkView::renderOnScreen(CDC* pDC)
	{
		CCGWorkDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);
		if (!pDoc)
			return;

		// Compute Normals and Polygons normals, add pointer to them to the Polygon


		HW2::World &w = HW2::World::get();
		HW2::Drawer &d = HW2::Drawer::get();
		HW2::Color bg = w.BackgroundColor;

		CRect windowRect;
		m_pDC->GetWindow()->GetClientRect(&windowRect);
		int width = windowRect.Width();
		int height = windowRect.Height();

		// Background
		CBrush bgColor(RGB(bg.r,bg.g,bg.b));   
		pDC->FillRect(&windowRect,&bgColor);   

		HW2::Z_Buffer z_buffer(width, height);
		for(unsigned int i = 0; i< w.polygons.size(); ++i)
		{
			HW2::PolygonData pd = d.generatePolygonData(w.polygons[i]);
			pd.draw(z_buffer);
		}
		HW2::ScreenPlotter screen(pDC);
		z_buffer.draw(screen);
	}


	void CCGWorkView::OnRenderOnScreen()
	{
		HW2::Lighter::get().sources[0].shadowVerification = 0;
		m_renderOnScreen = true;
		Invalidate();
	}

	void CCGWorkView::OnSetImageBackground()
	{
		HW2::Lighter::get().backImage = &(backgroundImage);//pavel
		SelectBackgroundImageDialog dialog;
		if(dialog.DoModal() != IDOK)
			return;
		m_imageBackground = true;
		string filename = dialog.filename;

		backgroundImage.wrapper.SetFileName(filename.c_str());
		backgroundImage.valid = true;
		backgroundImage.repeat = dialog.repeat;
		backgroundImage.wrapper.ReadPng();
	}






	void CCGWorkView::OnRenderOnFile()
	{
		HW2::Lighter::get().sources[0].shadowVerification = 0;
		lastRenderOnScreen = 1000;
		CRect windowRect;
		m_pDC->GetWindow()->GetClientRect(&windowRect);
		int width = windowRect.Width();
		int height = windowRect.Height();

		RenderToFileDialog dialog(width, height);
		if(dialog.DoModal() != IDOK)
			return;

		string filename = dialog.filename;
		HW2::Drawer oldDrawer = HW2::Drawer::get();

		height = dialog.height;
		width = dialog.width;

		HW2::World &w = HW2::World::get();
		HW2::Drawer &d = HW2::Drawer::get();
		//OnSize(0,width, height);

		d.resize(width, height);

		HW2::PngPlotter p(filename, width, height);

		render(p, height, width);

		p.write();
		HW2::Drawer::get() = oldDrawer;

		AfxMessageBox("Rendering complete");
	}


	void CCGWorkView::OnDraw(CDC* pDC)
	{
		CCGWorkDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);
		if (!pDoc)
			return;

		HW2::World &w = HW2::World::get();
		HW2::Drawer &d = HW2::Drawer::get();
		HW2::Color bg = w.BackgroundColor;

		d.setScreen(pDC);

		CRect windowRect;
		m_pDC->GetWindow()->GetClientRect(&windowRect);
		int width = windowRect.Width();
		int height = windowRect.Height();

		if(m_renderOnScreen)
		{
			m_renderOnScreen = false;
			lastRenderOnScreen = 0;
			HW2::ScreenPlotter p(pDC);
			render(p,height, width);
			//p.write();
			return;
		}
		lastRenderOnScreen ++;

		CRect rect;   
		GetClientRect(&rect);   
		CBrush bgColor(RGB(bg.r,bg.g,bg.b));   
		pDC->FillRect(&rect,&bgColor);   

		std::vector<HW2::ImageBitmap> &bitmaps = w.bitmaps;
		bitmaps.clear();
		bitmaps.reserve(w.polygons.size());

		for(unsigned int i = 0; i< w.polygons.size(); ++i)
			if(!m_backface_culling || d.transform(w.polygons[i].normal.unitVector).Z() > 0)
				bitmaps.push_back(d.generateBitmap(w.polygons[i]));
		std::sort(bitmaps.rbegin(), bitmaps.rend());

		for(unsigned int i = 0; i< bitmaps.size(); ++i)
		{
			bitmaps[i].draw();
		}

		if(m_bIsBoundingBox)
			d.drawEdges(w.boundingBox);
		if(m_bIsVertexNormals) 
			d.drawEdges(w.normals);
		if(m_bIsPolygonNormals)
			d.drawEdges(w.polygonsNormals);


		if(inAnimation)
		{
			inAnimation = false;
			HW2::World::get().BackgroundColor = HW2::Color(255,0,0);
			Invalidate();
		}

	}


	/////////////////////////////////////////////////////////////////////////////
	// CCGWorkView CGWork Finishing and clearing...

	void CCGWorkView::OnDestroy() 
	{
		CView::OnDestroy();

		// delete the DC
		if ( m_pDC ) {
			delete m_pDC;
		}
	}



	/////////////////////////////////////////////////////////////////////////////
	// User Defined Functions

	void CCGWorkView::RenderScene() {
		// do nothing. This is supposed to be overriden...

		return;
	}


	void CCGWorkView::OnFileLoad() 
	{
		TCHAR szFilters[] = _T ("IRIT Data Files (*.itd)|*.itd|All Files (*.*)|*.*||");

		CFileDialog dlg(TRUE, "itd", "*.itd", OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ,szFilters);

		if (dlg.DoModal () == IDOK) {
			m_strItdFileName = dlg.GetPathName();		// Full path and filename
			HW2::Lighter& l = HW2::Lighter::get();
			l.restart();
			PngWrapper p;
			HW2::World::get().reset();
			HW2::Drawer::get().reset();
			CGSkelProcessIritDataFiles(m_strItdFileName, 1, fineness);
			CRect windowRect;
			m_pDC->GetWindow()->GetClientRect(&windowRect);
			HW2::World::get().finishConstruction();
			HW2::Drawer::get().OnFinishFileLoad(windowRect.Width(), windowRect.Height());
			TRACE("%d\n",l.sources[0].direction.X());
			Invalidate();	// force a WM_PAINT for drawing.
		} 

	}





	// VIEW HANDLERS ///////////////////////////////////////////

	// Note: that all the following Message Handlers act in a similar way.
	// Each control or command has two functions associated with it.

	void CCGWorkView::OnViewOrthographic() 
	{
		m_nView = ID_VIEW_ORTHOGRAPHIC;
		HW2::World::get().isPerspective = m_bIsPerspective = false;
		Invalidate();		// redraw using the new view.
	}

	void CCGWorkView::OnUpdateViewOrthographic(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nView == ID_VIEW_ORTHOGRAPHIC);
	}

	void CCGWorkView::OnViewPerspective() 
	{
		m_nView = ID_VIEW_PERSPECTIVE;
		HW2::World::get().isPerspective = m_bIsPerspective = true;
		Invalidate();
	}

	void CCGWorkView::OnUpdateViewPerspective(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nView == ID_VIEW_PERSPECTIVE);
	}




	// ACTION HANDLERS ///////////////////////////////////////////

	void CCGWorkView::OnActionRotate() 
	{
		m_nAction = ID_ACTION_ROTATE;
	}

	void CCGWorkView::OnUpdateActionRotate(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAction == ID_ACTION_ROTATE);
	}

	void CCGWorkView::OnActionTranslate() 
	{
		m_nAction = ID_ACTION_TRANSLATE;
	}

	void CCGWorkView::OnUpdateActionTranslate(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAction == ID_ACTION_TRANSLATE);
	}

	void CCGWorkView::OnActionScale() 
	{
		m_nAction = ID_ACTION_SCALE;
	}

	void CCGWorkView::OnUpdateActionScale(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAction == ID_ACTION_SCALE);
	}




	// AXIS HANDLERS ///////////////////////////////////////////


	// Gets calles when the X button is pressed or when the Axis->X menu is selected.
	// The only thing we do here is set the ChildView member variable m_nAxis to the 
	// selected axis.
	void CCGWorkView::OnAxisX() 
	{
		m_nAxis = ID_AXIS_X;
	}

	// Gets called when windows has to repaint either the X button or the Axis pop up menu.
	// The control is responsible for its redrawing.
	// It sets itself disabled when the action is a Scale action.
	// It sets itself Checked if the current axis is the X axis.
	void CCGWorkView::OnUpdateAxisX(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAxis == ID_AXIS_X);
	}


	void CCGWorkView::OnAxisXY()
	{
		m_nAxis = ID_AXIS_XY;
	}


	void CCGWorkView::OnAxisY() 
	{
		m_nAxis = ID_AXIS_Y;
	}

	void CCGWorkView::OnUpdateAxisY(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAxis == ID_AXIS_Y);
	}


	void CCGWorkView::OnAxisZ() 
	{
		m_nAxis = ID_AXIS_Z;
	}

	void CCGWorkView::OnUpdateAxisZ(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nAxis == ID_AXIS_Z);
	}





	// OPTIONS HANDLERS ///////////////////////////////////////////




	// LIGHT SHADING HANDLERS ///////////////////////////////////////////

	void CCGWorkView::OnLightShadingFlat() 
	{
		m_nLightShading = ID_LIGHT_SHADING_FLAT;
		HW2::Lighter::get().shadingType = HW2::FLAT;
	}

	void CCGWorkView::OnUpdateLightShadingFlat(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nLightShading == ID_LIGHT_SHADING_FLAT);
	}


	void CCGWorkView::OnLightShadingGouraud() 
	{
		m_nLightShading = ID_LIGHT_SHADING_GOURAUD;
		HW2::Lighter::get().shadingType = HW2::GUARDED;
	}

	void CCGWorkView::OnUpdateLightShadingGouraud(CCmdUI* pCmdUI) 
	{
		pCmdUI->SetCheck(m_nLightShading == ID_LIGHT_SHADING_GOURAUD);
	}

	void CCGWorkView::OnLightShadingPhong(){

		m_nLightShading = ID_SHADING_PHONG;
		HW2::Lighter::get().shadingType = HW2::PHONG;

	}


	void CCGWorkView::OnUpdateLightShadingPhong(CCmdUI* pCmdUI){
		pCmdUI->SetCheck(m_nLightShading == ID_SHADING_PHONG);

	}

	

	void CCGWorkView::onUpdatTextureWood(){

		HW2::Lighter::get().shadingType = HW2::TEXTURE_WOOD;

	}

	void CCGWorkView::onUpdatTextureMarbel(){

		HW2::Lighter::get().shadingType = HW2::TEXTURE_MARBEL;

	}

	void CCGWorkView::onUpdatTextureRust(){

		HW2::Lighter::get().shadingType = HW2::TEXTURE_RUST;

	}
	
	void CCGWorkView::onUpdatTextureArmy(){

		HW2::Lighter::get().shadingType = HW2::TEXTURE_ARMY;

	}

	void CCGWorkView::onUpdatTextureEarth(){

		HW2::Lighter::get().shadingType = HW2::TEXTURE_EARTH;

	}


	void  CCGWorkView::onUpdateTextureReptileSkin(){
		HW2::Lighter::get().shadingType = HW2::TEXTURE_REPTILE_SKIN;

	}

	
	std::vector<HW2::Polygon> tmpPolyVec;

	void addShadowsForPolygonDirectional(HW2::Polygon& p,HW2::psLightSource& ls){

		for(int i = 0 ; i< p.coordinates.size()- 1 ;i++){
			
			HW2::Polygon shadowP(HW2::Color(0,0,0));
			
			shadowP.coordinates.push_back(p.coordinates[i]);
			shadowP.coordinates.push_back(p.coordinates[i+1]);
			HW2::Coordinates c1 = ((ls.direction/0.1) + p.coordinates[i]);
			HW2::Coordinates c2 =((ls.direction/0.1) + p.coordinates[i + 1]);
			shadowP.coordinates.push_back(c1);
			shadowP.coordinates.push_back(c2);
		    
			shadowP.computeNormal();

			shadowP.name = "Shadow";
			shadowP.color.alpha = 0;
			tmpPolyVec.push_back(shadowP);	
			//take two points and construct a new polygon
			//add normal to the polygon
			//name the polygon shadow
			//add transperancy
		}


		HW2::Polygon shadowP(HW2::Color(0,0,0));
			
			shadowP.coordinates.push_back(p.coordinates[p.coordinates.size() - 1]);
			shadowP.coordinates.push_back(p.coordinates[0]);
			shadowP.coordinates.push_back(((ls.direction/0.1) + p.coordinates[p.coordinates.size() - 1]));
			shadowP.coordinates.push_back(((ls.direction/0.1) + p.coordinates[0]));
			shadowP.name = "Shadow";
			shadowP.computeNormal();
			tmpPolyVec.push_back(shadowP);	


	}



	void constructPolygons(int sourceNumber){
		HW2::World& w = HW2::World::get();
		HW2::Lighter& l = HW2::Lighter::get();
		int numOfOriginalPolygons = w.polygons.size();
		for (int i = 0 ; i < numOfOriginalPolygons;i++){
			//need to add if
			if (w.polygons[i].name.compare("Shadow")!=0){
				HW2::Polygon& p = w.polygons[i];
				HW2::psLightSource& ls = l.sources[sourceNumber];
				addShadowsForPolygonDirectional(p,ls);
			}
		}
	}


	void CCGWorkView::addShadows(){
		/*HW2::World& w = HW2::World::get();
		HW2::Lighter& l = HW2::Lighter::get();

		for (int i = 0 ; i < 8 ;i++){
			if (l.sources[i].enabled == true){
				constructPolygons(i);
			}
		}
		
		for (int i = 0 ; i<tmpPolyVec.size();i++)
			w.polygons.push_back(tmpPolyVec[i]);*/
		HW2::Lighter& l = HW2::Lighter::get();

		if (l.shadows == false){
			l.shadows = true;
			if (l.sources[0].ShadowPointsVec == NULL)
			 l.sources[0].ShadowPointsVec = new HW2::Coordinates[10000000];

		}else{
			l.shadows = false;
				//delete[]  l.sources[0].ShadowPointsVec;
			for (int i = 0 ; i< 10000000;i++){
				l.sources[0].ShadowPointsVec[i].X() = 0;
				l.sources[0].ShadowPointsVec[i].Y() = 0;
				l.sources[0].ShadowPointsVec[i].Z() = 0;
			}

		}
		


	}

	void CCGWorkView::onUpdateTextureCustom(){
		textureDlg2 dlg;
		HW2::World &w = HW2::World::get();
		std::vector<string> objNames;
		HW2::Lighter& l = HW2::Lighter::get();
		bool contains =false;
		if(l.objectNames.size() == 0){
			for(int i = 0; i < w.polygons.size() ; i++){

				for(int j = 0; j< objNames.size();j++){
					string s = w.polygons[i].name;
					string t = objNames[j];
					if ((t.compare(s))==0)
						contains = true;
				}

				if (contains == false){
					//CString str = w.polygons[i].name.c_str();
					//str.Format(_T("sadfasdf"));
					//dlg.objectList.AddString(str);
					objNames.push_back(w.polygons[i].name);
					dlg.objNameArray.push_back(w.polygons[i].name);
					dlg.objTypeArray.push_back("PHONG");
					dlg.textureAns.push_back(2);
				}
				contains = false;
			}
		}else{
			dlg.objNameArray = l.objectNames;
			for (int i =0 ; i< l.objectNames.size() ; i++){
					
				dlg.textureAns.push_back(static_cast<int>(l.objectShading[i]));
				dlg.objTypeArray.push_back(l.objectShadingNames[i]);
			}
			

		}
		if (dlg.DoModal() == IDOK) {
			
		

		l.objectNames.clear();
		l.objectShading.clear();
		l.objectShadingNames.clear();
		for (int i = 0 ; i < dlg.objNameArray.size(); i++){
				
				//l.objectNames.push_back(objNames[i]);
			l.objectNames.push_back(dlg.objNameArray[i]);
				int type = dlg.textureAns[i];
				l.objectShading.push_back(static_cast<HW2::ShadingType>(dlg.textureAns[i]));
				l.objectShadingNames.push_back(dlg.objTypeArray[i]);
			}
		}
		
		
	}

	// LIGHT SETUP HANDLER ///////////////////////////////////////////


	void CCGWorkView::onUpdatMaterialvars(){

		CMaterialDlg dlg;
		HW2::Lighter &l = HW2::Lighter::get();

		dlg.m_ambient = l.k_ambient ;

		dlg.m_diffuse = l.k_diffusive;

		dlg.m_specular = l.n_shininess;
		dlg.m_shininess = l.k_specular;

		if (dlg.DoModal()){

			l.k_ambient = dlg.m_ambient;
			l.k_diffusive = dlg.m_diffuse;
			l.n_shininess = dlg.m_specular;
			l.k_specular = dlg.m_shininess;

		}


	}

	void CCGWorkView::OnLightConstants() 
	{
		CLightDialog dlg;
		HW2::Lighter &l = HW2::Lighter::get();


		for (int id=LIGHT_ID_1;id<MAX_LIGHT;id++)
		{	 
			m_lights[id].colorR = l.sources[id].color.r;
			m_lights[id].colorG = l.sources[id].color.g;
			m_lights[id].colorB = l.sources[id].color.b;

			m_lights[id].dirX = l.sources[id].displayDirection.X();
			m_lights[id].dirY = l.sources[id].displayDirection.Y();
			m_lights[id].dirZ = l.sources[id].displayDirection.Z();

			m_lights[id].posX = l.sources[id].position.X();
			m_lights[id].posY = l.sources[id].position.Y();
			m_lights[id].posZ = l.sources[id].position.Z();

			m_lights[id].enabled = l.sources[id].enabled;
			m_lights[id].type = l.sources[id].type;


			dlg.SetDialogData((LightID)id,m_lights[id]);
		}
		dlg.SetDialogData(LIGHT_ID_AMBIENT,m_ambientLight);

		if (dlg.DoModal() == IDOK) 
		{
			for (int id=LIGHT_ID_1;id<MAX_LIGHT;id++)
			{
				m_lights[id] = dlg.GetDialogData((LightID)id);
				l.sources[id].setPosition(m_lights[id].posX,m_lights[id].posY,m_lights[id].posZ);
				l.sources[id].setDirection(m_lights[id].dirX,m_lights[id].dirY,m_lights[id].dirZ);
				l.sources[id].enabled = m_lights[id].enabled;
				l.sources[id].setColor( m_lights[id].colorR,m_lights[id].colorG,m_lights[id].colorB);
				l.sources[id].type =  m_lights[id].type;
				l.sources[id].setViewMode(m_lights[id].space);

			}
			m_ambientLight = dlg.GetDialogData(LIGHT_ID_AMBIENT);
			l.setAmbient(m_ambientLight.colorR,m_ambientLight.colorG,m_ambientLight.colorB);
		}	
		Invalidate();
	}




	void CCGWorkView::OnMouseMove(UINT nFlags, CPoint point){

		HW2::Drawer &d = HW2::Drawer::get();
		if (nFlags == MK_LBUTTON)
		{
			double deltaX = point.x - mouseDown.X();
			double deltaY = point.y - mouseDown.Y();

			if(deltaX != 0 && mouseDown.X() != -1)
			{
				switch(m_nAction)
				{
				case ID_ACTION_TRANSLATE:
					deltaX *= (translateSensitivity / 10.0);
					deltaY *= (translateSensitivity / 10.0);
					switch(m_nAxis)
					{
					case ID_AXIS_X:
						d.translate(deltaX,0,0);
						break;
					case ID_AXIS_Y:
						d.translate(0,deltaX,0);
						break;
					case ID_AXIS_Z:
						d.translate(0,0,deltaX);
						break;
					case ID_AXIS_XY:
						d.translate(deltaX, deltaY, 0);
						break;

					}
					break;
				case ID_ACTION_ROTATE:
					{
						double angle = deltaX / 100;
						angle *= (rotateSensitivity/10.0);
						double angleY = deltaY / 100;
						angleY *= (rotateSensitivity/10.0);
						switch(m_nAxis)
						{
						case ID_AXIS_X:
							d.rotateX(angle);
							break;
						case ID_AXIS_Y:
							d.rotateY(angle);
							break;
						case ID_AXIS_Z:
							d.rotateZ(angle);
							break;
						case ID_AXIS_XY:
							d.rotateX(angle);
							d.rotateY(angleY);
							break;
						}
						break;
					}
				case ID_ACTION_SCALE:
					{
						double effect = scaleSensitivity * abs(deltaX) / 10000;
						// We have: 0 < effect < 1
						double ratio = (deltaX > 0 ? 1+effect :  (1/(1+effect)));
						double effectY = scaleSensitivity * abs(deltaY) / 10000;
						// We have: 0 < effect < 1
						double ratioY = (deltaY > 0 ? 1+effectY :  (1/(1+effectY)));

						switch(m_nAxis)
						{
						case ID_AXIS_X:
							d.apply(HW2::Matrix::scale(ratio,1,1));
							break;
						case ID_AXIS_Y:
							d.apply(HW2::Matrix::scale(1,ratio,1));
							break;
						case ID_AXIS_Z:
							d.apply(HW2::Matrix::scale(1,1,ratio));
							break;
						case ID_AXIS_XY:
							d.apply(HW2::Matrix::scale(ratio,1,1));
							d.apply(HW2::Matrix::scale(1,ratioY, 1));
							break;

						}
						break;
					}
				}
				//	HW2::Lighter::get().transformLightSources();
				Invalidate();
			}

			mouseDown.X() = point.x;
			mouseDown.Y() = point.y;
		}
	}	

	void CCGWorkView::OnLButtonDown(UINT nFlags, CPoint point)
	{
		TRACE("point ckicked: %d %d \n",point.x,point.y);
		
		if (nFlags == MK_LBUTTON){
			mouseDown.X() = point.x;
			mouseDown.Y() = point.y;

			
			//int i = HW2::World::get().getPolygonByPoint(point.x,point.y); //PAVEL
			if(m_bIsClickToLight)
			{
				HW2::ImageBitmap *i = HW2::World::get().getPolygonByPoint2(point.x, point.y);
				if(i != 0)
				{
					i->p->color = HW2::Color(0,255,0);
					Invalidate();
				}
			}
		}
	}

	void CCGWorkView::OnUpdateBoundingBox()
	{
		m_bIsBoundingBox = !m_bIsBoundingBox;
		Invalidate();
	}

	void CCGWorkView::OnUpdateVertexNormals()
	{
		m_bIsVertexNormals = !m_bIsVertexNormals;
		Invalidate();
	}

	void CCGWorkView::OnUpdatePolygonsNormals()
	{
		m_bIsPolygonNormals = !m_bIsPolygonNormals;
		Invalidate();
	}

	void CCGWorkView::OnIncreasePerspectiveD10() {
		HW2::Drawer::get().modifyD(1.1);
		Invalidate();
	}

	void CCGWorkView::OnDecreasePerspectiveD10(){
		HW2::Drawer::get().modifyD(1/1.1);
		Invalidate();
	}
	void CCGWorkView::onActivateFog(){
		HW2::Lighter& l = HW2::Lighter::get();
		if (l.fogActivated){
			l.fogActivated =false;

		}else{

			l.fogActivated =true;

		}

	}


	static HW2::Color getColorFromDialog()
	{
		CColorDialog dlg;
		dlg.DoModal();
		COLORREF c =  dlg.GetColor();
		return HW2::Color(GetRValue(c), GetGValue(c), GetBValue(c));
	}

	void CCGWorkView::onSetFogColor(){
		HW2::Lighter::get().fogColor = getColorFromDialog();
		Invalidate();

	}

	void CCGWorkView::OnChangeColorBackground(){
		HW2::World::get().BackgroundColor = getColorFromDialog();
		Invalidate();
	}
	void CCGWorkView::OnChangeColorNormals(){
		HW2::Color c = getColorFromDialog();
		HW2::World &w = HW2::World::get();
		for(unsigned i = 0; i < w.normals.size(); i++)
			w.normals[i].color = c;
		for(unsigned i = 0; i < w.polygonsNormals.size(); i++)
			w.polygonsNormals[i].color = c;
		if(m_bIsVertexNormals || m_bIsPolygonNormals)
			Invalidate();

	}
	void CCGWorkView::OnChangeColorVertex(){
		HW2::Color c = getColorFromDialog();
		HW2::World &w = HW2::World::get();
		for(unsigned i = 0; i < w.edges.size(); i++)
			w.edges[i].color = c;
		for(unsigned i = 0; i < w.polygons.size(); i++)
			w.polygons[i].color = c;
		Invalidate();
	}

	void CCGWorkView::OnMouseSensitivity()
	{
		SensibilityDialog d(rotateSensitivity, scaleSensitivity, translateSensitivity);
		if(d.DoModal() != IDOK)
			return;
		if((rotateSensitivity = d.rotateValue) == 0)
			rotateSensitivity = 1;
		if((scaleSensitivity = d.scaleValue) == 0)
			scaleSensitivity = 1;
		if((translateSensitivity = d.translateValue) == 0)
			translateSensitivity = 1;
		if(rotateSensitivity == 100)
			rotateSensitivity = 99;
		if(translateSensitivity == 100)
			translateSensitivity = 99;
		if(scaleSensitivity == 100)
			scaleSensitivity = 99;
	}

	void CCGWorkView::OnFinenessControl()
	{
		FinenessDialog d(fineness);
		if(d.DoModal() != IDOK)
			return;
		fineness = d.fineness;
	}

	void CCGWorkView::OnObjectSpace()
	{
		HW2::Drawer::get().objectSpace = true;
	}
	void CCGWorkView::OnViewSpace()
	{
		HW2::Drawer::get().objectSpace = false;
	}
	void CCGWorkView::OnSetCTL()
	{
		m_bIsClickToLight = true;
	}
	void CCGWorkView::OnUnSetCTL()
	{
		m_bIsClickToLight = false;
	}


	void CCGWorkView::OnNormalInverse()
	{
		HW2::World &w = HW2::World::get();
		for(unsigned int i = 0; i < w.polygons.size(); ++i)
		{
			HW2::Polygon &p = w.polygons[i];
			p.normal = p.normal.inverse();
			for(unsigned int j = 0; j < p.normals.size(); ++j)
			{
				p.normals[j] = p.normals[j].inverse();
			}
		}
		for(unsigned int i = 0; i < w.normals.size(); ++i)
		{
			w.normals[i] = w.normals[i].inverse();
		}
		for(unsigned int i = 0; i < w.polygonsNormals.size(); ++i)
		{
			w.polygonsNormals[i] = w.polygonsNormals[i].inverse();
		}
	}


	void CCGWorkView::OnOptionsSwitchbackfaceculling()
	{
		m_backface_culling = !m_backface_culling;
		Invalidate();
	}


	void CCGWorkView::OnTransparencyEnable()
	{
		m_transparency = true;
		// TODO: Add your command handler code here
	}


	void CCGWorkView::OnTransparencyDisable()
	{
		m_transparency = false;
	}



	afx_msg void CCGWorkView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
	{
		/*
		if(nChar == VK_RETURN)
		{
		drawers.push_back(HW2::Drawer::get());
		}
		if(nChar == VK_DELETE)
		{
		inAnimation = true;
		HW2::World::get().BackgroundColor = HW2::Color(0,255,0);
		Invalidate();
		}
		*/

	}


	void CCGWorkView::OnAntialiasingNone()
	{
		HW2::World::get().filterType = 0;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingBox()
	{
		HW2::World::get().filterType = 1;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingGauss()
	{
		HW2::World::get().filterType = 2;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingTriangle()
	{
		HW2::World::get().filterType = 3;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingSinc()
	{
		HW2::World::get().filterType = 4;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingFiltersize3x3()
	{
		HW2::World::get().filterSize = 3;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::OnAntialiasingFilterSize5x5()
	{
		HW2::World::get().filterSize = 5;
		if(lastRenderOnScreen < 2)
			OnRenderOnScreen();
	}


	void CCGWorkView::onAddBase(){
	//	static BOOL baseActivated;
		if (HW2::Lighter::get().baseActivated == false){
			HW2::World& w = HW2::World::get();
			HW2::Color pc = getColorFromDialog();
			HW2::Polygon p(pc);
			
			int min = w.minPoint.Y();
			


			p.coordinates.push_back(HW2::Coordinates(-20,min-0.8,-20));
			p.coordinates.push_back(HW2::Coordinates(-20,min-0.8,20));
			p.coordinates.push_back(HW2::Coordinates(20,min-0.8,20));
			p.coordinates.push_back(HW2::Coordinates(20,min-0.8,-20));
			HW2::Coordinates c1(-1,1,-1);
			c1.normalize();
			p.normals.push_back(c1);

			HW2::Coordinates c2(-1,1,1);
			c2.normalize();
			p.normals.push_back(c2);

			HW2::Coordinates c3(1,1,1);
			c3.normalize();
			p.normals.push_back(c3);

			HW2::Coordinates c4(1,1,-1);
			c4.normalize();
			p.normals.push_back(c4);

			p.k= HW2::Color(0,1,0);
			p.ks= HW2::Color(0,1,0);

			p.name = "Base_Proj";

			p.normal.unitVector = HW2::Coordinates(0,1,0);

			w.polygons.push_back(p);
			HW2::Lighter::get().baseActivated = true;
		}else{
			HW2::World& w = HW2::World::get();
			w.polygons.pop_back();

			HW2::Lighter::get().baseActivated = false;
		}


	}